package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// handleHome 处理主页
func handleHome(w http.ResponseWriter, r *http.Request) {
	tmpl := `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>向量测试工具</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: 'Microsoft YaHei', Arial, sans-serif; background: #f5f5f5; }
        .container { max-width: 1200px; margin: 0 auto; padding: 20px; }
        .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 10px; margin-bottom: 30px; text-align: center; }
        .card { background: white; border-radius: 10px; padding: 25px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        .form-group { margin-bottom: 20px; }
        label { display: block; margin-bottom: 8px; font-weight: bold; color: #333; }
        input, select, textarea { width: 100%; padding: 12px; border: 2px solid #ddd; border-radius: 6px; font-size: 14px; }
        input:focus, select:focus, textarea:focus { border-color: #667eea; outline: none; }
        .checkbox-group { display: flex; flex-wrap: wrap; gap: 15px; margin-top: 10px; }
        .checkbox-item { display: flex; align-items: center; }
        .checkbox-item input { width: auto; margin-right: 8px; }
        .btn { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 30px; border: none; border-radius: 6px; cursor: pointer; font-size: 16px; font-weight: bold; }
        .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 15px rgba(0,0,0,0.2); }
        .btn:disabled { background: #ccc; cursor: not-allowed; transform: none; }
        .progress { background: #f0f0f0; border-radius: 10px; overflow: hidden; margin: 20px 0; }
        .progress-bar { background: linear-gradient(90deg, #667eea, #764ba2); height: 30px; width: 0%; transition: width 0.3s; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; }
        .status { padding: 15px; border-radius: 6px; margin: 10px 0; }
        .status.info { background: #e3f2fd; border-left: 4px solid #2196f3; }
        .status.success { background: #e8f5e8; border-left: 4px solid #4caf50; }
        .status.error { background: #ffebee; border-left: 4px solid #f44336; }
        .search-results { margin-top: 20px; }
        .result-item { background: #f9f9f9; border-left: 4px solid #667eea; padding: 15px; margin: 10px 0; border-radius: 6px; }
        .result-score { color: #667eea; font-weight: bold; }
        .result-path { color: #666; font-size: 12px; margin-bottom: 5px; cursor: pointer; }
        .result-path:hover { color: #667eea; text-decoration: underline; }
        .result-content { line-height: 1.6; }
        .two-column { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
        @media (max-width: 768px) { .two-column { grid-template-columns: 1fr; } }
        
        /* 文件查看弹窗样式 */
        .modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); }
        .modal-content { background-color: #fefefe; margin: 2% auto; padding: 0; border-radius: 10px; width: 90%; max-width: 1000px; height: 90%; display: flex; flex-direction: column; }
        .modal-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 10px 10px 0 0; display: flex; justify-content: space-between; align-items: center; }
        .modal-header h2 { margin: 0; }
        .close { color: white; font-size: 28px; font-weight: bold; cursor: pointer; }
        .close:hover { opacity: 0.7; }
        .modal-body { flex: 1; overflow: hidden; display: flex; flex-direction: column; }
        .file-info { padding: 15px; background: #f8f9fa; border-bottom: 1px solid #dee2e6; }
        .file-content { flex: 1; overflow: auto; }
        .line-numbers { background: #f8f9fa; border-right: 1px solid #dee2e6; padding: 10px; font-family: 'Courier New', monospace; font-size: 12px; color: #666; min-width: 50px; text-align: right; }
        .content-area { display: flex; height: 100%; }
        .content-text { flex: 1; padding: 10px; font-family: 'Courier New', monospace; font-size: 14px; line-height: 1.5; white-space: pre-wrap; overflow: auto; }
        .highlight-line { background-color: #fff3cd; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🚀 向量测试工具</h1>
            <p>基于向量数据库的本地知识库测试平台</p>
        </div>

        <div class="two-column">
            <div>
                <div class="card">
                    <h2>📁 文档索引</h2>
                    <form id="indexForm">
                        <div class="form-group">
                            <label for="folderPath">目标文件夹路径:</label>
                            <input type="text" id="folderPath" placeholder="例如: ./docs" value="./docs/样本知识 国资委监管制度">
                        </div>
                        
                        <div class="form-group">
                            <label>选择文件类型:</label>
                            <div class="checkbox-group">
                                <div class="checkbox-item">
                                    <input type="checkbox" id="md" value="md" checked>
                                    <label for="md">Markdown (.md)</label>
                                </div>
                                <div class="checkbox-item">
                                    <input type="checkbox" id="txt" value="txt" checked>
                                    <label for="txt">文本 (.txt)</label>
                                </div>
                                <div class="checkbox-item">
                                    <input type="checkbox" id="pdf" value="pdf">
                                    <label for="pdf">PDF (.pdf)</label>
                                </div>
                                <div class="checkbox-item">
                                    <input type="checkbox" id="docx" value="docx">
                                    <label for="docx">Word (.docx)</label>
                                </div>
                            </div>
                        </div>
                        
                        <div class="form-group">
                            <label for="chunkSize">分片大小 (字符数):</label>
                            <input type="number" id="chunkSize" value="1000" min="100" max="5000">
                        </div>
                        
                        <button type="submit" class="btn" id="indexBtn">开始索引</button>
                    </form>
                    
                    <div id="indexStatus" style="display: none;">
                        <div class="progress">
                            <div class="progress-bar" id="progressBar">0%</div>
                        </div>
                        <div id="statusMessage" class="status info">准备开始...</div>
                    </div>
                </div>
            </div>

            <div>
                <div class="card">
                    <h2>🔍 向量搜索</h2>
                    <form id="searchForm">
                        <div class="form-group">
                            <label for="searchQuery">搜索内容:</label>
                            <textarea id="searchQuery" rows="3" placeholder="输入要搜索的内容..."></textarea>
                        </div>
                        
                        <div class="form-group">
                            <label for="topK">返回结果数量:</label>
                            <select id="topK">
                                <option value="5">5个结果</option>
                                <option value="10">10个结果</option>
                                <option value="20">20个结果</option>
                            </select>
                        </div>
                        
                        <div class="form-group">
                            <label for="threshold">相似度阈值:</label>
                            <select id="threshold">
                                <option value="0.1">0.1 (宽松)</option>
                                <option value="0.3" selected>0.3 (中等)</option>
                                <option value="0.5">0.5 (严格)</option>
                                <option value="0.7">0.7 (很严格)</option>
                            </select>
                        </div>
                        
                        <button type="submit" class="btn">搜索</button>
                    </form>
                    
                    <div id="searchResults" class="search-results"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- 文件查看弹窗 -->
    <div id="fileModal" class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <h2 id="modalTitle">文件内容查看</h2>
                <span class="close" onclick="closeFileModal()">&times;</span>
            </div>
            <div class="modal-body">
                <div class="file-info" id="fileInfo">
                    <strong>文件信息加载中...</strong>
                </div>
                <div class="file-content">
                    <div class="content-area">
                        <div class="line-numbers" id="lineNumbers"></div>
                        <div class="content-text" id="fileContentText"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        let indexing = false;
        
        // 索引表单提交
        document.getElementById('indexForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            
            if (indexing) return;
            
            const folderPath = document.getElementById('folderPath').value;
            const chunkSize = parseInt(document.getElementById('chunkSize').value);
            
            // 获取选中的文件类型
            const fileTypes = [];
            document.querySelectorAll('input[type="checkbox"]:checked').forEach(cb => {
                fileTypes.push(cb.value);
            });
            
            if (!folderPath || fileTypes.length === 0) {
                alert('请填写文件夹路径并选择至少一种文件类型');
                return;
            }
            
            indexing = true;
            document.getElementById('indexBtn').disabled = true;
            document.getElementById('indexBtn').textContent = '索引中...';
            document.getElementById('indexStatus').style.display = 'block';
            
            try {
                const response = await fetch('/api/index', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ folder_path: folderPath, file_types: fileTypes, chunk_size: chunkSize })
                });
                
                const result = await response.json();
                
                if (result.success) {
                    document.getElementById('statusMessage').className = 'status success';
                    document.getElementById('statusMessage').textContent = result.message;
                    document.getElementById('progressBar').style.width = '100%';
                    document.getElementById('progressBar').textContent = '100%';
                } else {
                    document.getElementById('statusMessage').className = 'status error';
                    document.getElementById('statusMessage').textContent = result.message;
                }
            } catch (error) {
                document.getElementById('statusMessage').className = 'status error';
                document.getElementById('statusMessage').textContent = '索引失败: ' + error.message;
            }
            
            indexing = false;
            document.getElementById('indexBtn').disabled = false;
            document.getElementById('indexBtn').textContent = '开始索引';
        });
        
        // 搜索表单提交
        document.getElementById('searchForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            
            const query = document.getElementById('searchQuery').value;
            const topK = parseInt(document.getElementById('topK').value);
            const threshold = parseFloat(document.getElementById('threshold').value);
            
            if (!query.trim()) {
                alert('请输入搜索内容');
                return;
            }
            
            const resultsDiv = document.getElementById('searchResults');
            resultsDiv.innerHTML = '<div class="status info">搜索中...</div>';
            
            try {
                const response = await fetch('/api/search', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ query: query, top_k: topK, threshold: threshold })
                });
                
                const result = await response.json();
                
                if (result.success) {
                    displaySearchResults(result.results);
                } else {
                    resultsDiv.innerHTML = '<div class="status error">' + result.message + '</div>';
                }
            } catch (error) {
                resultsDiv.innerHTML = '<div class="status error">搜索失败: ' + error.message + '</div>';
            }
        });
        
        // 显示搜索结果
        function displaySearchResults(results) {
            const resultsDiv = document.getElementById('searchResults');
            
            if (results.length === 0) {
                resultsDiv.innerHTML = '<div class="status info">没有找到匹配的结果</div>';
                return;
            }
            
            let html = '<h3>搜索结果 (' + results.length + '个)</h3>';
            
            results.forEach((result, index) => {
                html += '<div class="result-item">';
                html += '<div class="result-path" onclick="viewFile(\'' + result.file_path.replace(/\\/g, '\\\\').replace(/'/g, "\\'") + '\', ' + result.line_start + ', ' + result.line_end + ')">📄 ' + result.file_path + ' (第' + result.line_start + '-' + result.line_end + '行)</div>';
                html += '<div class="result-score">相似度: ' + (result.score * 100).toFixed(1) + '%</div>';
                html += '<div class="result-content">' + result.content.substring(0, 300) + (result.content.length > 300 ? '...' : '') + '</div>';
                html += '</div>';
            });
            
            resultsDiv.innerHTML = html;
        }
        
        // 查看文件内容
        async function viewFile(filePath, lineStart, lineEnd) {
            console.log('查看文件:', filePath, '行号:', lineStart, '-', lineEnd);
            
            try {
                const response = await fetch('/api/file?path=' + encodeURIComponent(filePath));
                const result = await response.json();
                
                if (result.success) {
                    showFileModal(result, lineStart, lineEnd);
                } else {
                    alert('获取文件内容失败: ' + result.message);
                }
            } catch (error) {
                alert('获取文件内容失败: ' + error.message);
            }
        }
        
        // 显示文件查看弹窗
        function showFileModal(fileData, highlightStart, highlightEnd) {
            const modal = document.getElementById('fileModal');
            const modalTitle = document.getElementById('modalTitle');
            const fileInfo = document.getElementById('fileInfo');
            const lineNumbers = document.getElementById('lineNumbers');
            const fileContentText = document.getElementById('fileContentText');
            
            // 设置标题
            modalTitle.textContent = fileData.file_name;
            
            // 设置文件信息
            fileInfo.innerHTML = 
                '<strong>文件路径:</strong> ' + fileData.file_path + '<br>' +
                '<strong>文件大小:</strong> ' + formatFileSize(fileData.file_size) + '<br>' +
                '<strong>修改时间:</strong> ' + fileData.modified_at + '<br>' +
                '<strong>总行数:</strong> ' + fileData.line_count;
            
            // 生成行号
            let lineNumbersHtml = '';
            let contentHtml = '';
            
            fileData.lines.forEach((line, index) => {
                const lineNum = index + 1;
                const isHighlight = lineNum >= highlightStart && lineNum <= highlightEnd;
                
                lineNumbersHtml += '<div' + (isHighlight ? ' class="highlight-line"' : '') + '>' + lineNum + '</div>';
                contentHtml += '<div' + (isHighlight ? ' class="highlight-line"' : '') + '>' + escapeHtml(line) + '</div>';
            });
            
            lineNumbers.innerHTML = lineNumbersHtml;
            fileContentText.innerHTML = contentHtml;
            
            // 显示弹窗
            modal.style.display = 'block';
            
            // 滚动到高亮行
            if (highlightStart > 0) {
                setTimeout(() => {
                    const highlightElement = fileContentText.querySelector('.highlight-line');
                    if (highlightElement) {
                        highlightElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
                    }
                }, 100);
            }
        }
        
        // 关闭文件查看弹窗
        function closeFileModal() {
            document.getElementById('fileModal').style.display = 'none';
        }
        
        // 点击弹窗外部关闭
        window.onclick = function(event) {
            const modal = document.getElementById('fileModal');
            if (event.target === modal) {
                closeFileModal();
            }
        }
        
        // 格式化文件大小
        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const sizes = ['Bytes', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }
        
        // HTML转义
        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }
        
        // 定期更新索引状态
        setInterval(async () => {
            if (indexing) {
                try {
                    const response = await fetch('/api/status');
                    const status = await response.json();
                    
                    if (status.is_running) {
                        const progress = Math.round((status.processed_files / status.total_files) * 100);
                        document.getElementById('progressBar').style.width = progress + '%';
                        document.getElementById('progressBar').textContent = progress + '%';
                        document.getElementById('statusMessage').textContent = 
                            '正在处理: ' + status.current_file + ' (' + status.processed_files + '/' + status.total_files + ')';
                    }
                } catch (error) {
                    console.error('获取状态失败:', error);
                }
            }
        }, 1000);
    </script>
</body>
</html>
`
	
	t, err := template.New("home").Parse(tmpl)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	t.Execute(w, nil)
}

// handleIndex 处理索引请求
func handleIndex(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	
	var req IndexRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		respondJSON(w, map[string]interface{}{
			"success": false,
			"message": "请求格式错误: " + err.Error(),
		})
		return
	}
	
	fmt.Printf("🎯 开始索引任务\n")
	fmt.Printf("📁 目标文件夹: %s\n", req.FolderPath)
	fmt.Printf("📋 文件类型: %v\n", req.FileTypes)
	fmt.Printf("✂️  分片大小: %d\n", req.ChunkSize)
	
	// 更新索引状态
	indexStatus.IsRunning = true
	indexStatus.Progress = 0
	indexStatus.StartTime = time.Now()
	indexStatus.Message = "正在扫描文件..."
	
	go func() {
		defer func() {
			indexStatus.IsRunning = false
			fmt.Printf("✅ 索引任务完成\n")
		}()
		
		// 创建文档处理器和向量化器
		processor := NewDocumentProcessor(req.ChunkSize)
		vectorizer := NewSimpleVectorizer(256) // 256维向量
		
		// 扫描文件
		files, err := processor.ProcessFolder(req.FolderPath, req.FileTypes)
		if err != nil {
			indexStatus.Message = "扫描文件失败: " + err.Error()
			fmt.Printf("❌ 扫描文件失败: %v\n", err)
			return
		}
		
		indexStatus.TotalFiles = len(files)
		indexStatus.ProcessedFiles = 0
		
		if len(files) == 0 {
			indexStatus.Message = "没有找到匹配的文件"
			fmt.Printf("⚠️  没有找到匹配的文件\n")
			return
		}
		
		// 清空现有向量数据
		if err := vectorDB.Clear(); err != nil {
			indexStatus.Message = "清空向量数据库失败: " + err.Error()
			fmt.Printf("❌ 清空向量数据库失败: %v\n", err)
			return
		}
		
		// 处理每个文件
		totalChunks := 0
		for i, filePath := range files {
			indexStatus.CurrentFile = filepath.Base(filePath)
			indexStatus.ProcessedFiles = i
			indexStatus.Progress = (i * 100) / len(files)
			
			fmt.Printf("\n📄 处理文件 %d/%d: %s\n", i+1, len(files), filePath)
			
			// 处理文档
			chunks, err := processor.ProcessFile(filePath)
			if err != nil {
				fmt.Printf("❌ 处理文件失败: %v\n", err)
				continue
			}
			
			// 向量化每个分片
			for _, chunk := range chunks {
				vector := vectorizer.Vectorize(chunk.Content)
				
				// 创建向量项
				item := VectorItem{
					ID:         fmt.Sprintf("%s_chunk_%d", filePath, chunk.Index),
					Vector:     vector,
					Content:    chunk.Content,
					FilePath:   filePath,
					ChunkIndex: chunk.Index,
					LineStart:  chunk.LineStart,
					LineEnd:    chunk.LineEnd,
					Metadata: map[string]interface{}{
						"file_name":    filepath.Base(filePath),
						"file_ext":     filepath.Ext(filePath),
						"chunk_size":   len(chunk.Content),
						"processed_at": time.Now().Format(time.RFC3339),
					},
				}
				
				// 添加到向量数据库
				if err := vectorDB.Add(item); err != nil {
					fmt.Printf("❌ 添加向量失败: %v\n", err)
					continue
				}
				
				totalChunks++
				fmt.Printf("✅ 添加分片 %d (行 %d-%d)\n", chunk.Index, chunk.LineStart, chunk.LineEnd)
			}
		}
		
		indexStatus.ProcessedFiles = len(files)
		indexStatus.Progress = 100
		indexStatus.Message = fmt.Sprintf("索引完成！处理了 %d 个文件，生成了 %d 个向量分片", len(files), totalChunks)
		
		fmt.Printf("\n🎉 索引任务完成！\n")
		fmt.Printf("📊 统计信息:\n")
		fmt.Printf("   - 处理文件数: %d\n", len(files))
		fmt.Printf("   - 生成分片数: %d\n", totalChunks)
		fmt.Printf("   - 向量维度: %d\n", 256)
		fmt.Printf("   - 耗时: %v\n", time.Since(indexStatus.StartTime))
	}()
	
	respondJSON(w, map[string]interface{}{
		"success": true,
		"message": "索引任务已开始",
	})
}

// handleSearch 处理搜索请求
func handleSearch(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	
	var req SearchRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		respondJSON(w, map[string]interface{}{
			"success": false,
			"message": "请求格式错误: " + err.Error(),
		})
		return
	}
	
	fmt.Printf("\n🔍 开始搜索\n")
	fmt.Printf("📝 查询内容: %s\n", req.Query)
	fmt.Printf("🎯 返回数量: %d\n", req.TopK)
	fmt.Printf("📊 相似度阈值: %.2f\n", req.Threshold)
	
	// 向量化查询文本
	vectorizer := NewSimpleVectorizer(256)
	queryVector := vectorizer.Vectorize(req.Query)
	
	// 执行搜索
	results := vectorDB.Search(queryVector, req.TopK, req.Threshold)
	
	fmt.Printf("✅ 搜索完成，找到 %d 个结果\n", len(results))
	for i, result := range results {
		fmt.Printf("   %d. %s (相似度: %.3f)\n", i+1, filepath.Base(result.FilePath), result.Score)
	}
	
	respondJSON(w, map[string]interface{}{
		"success": true,
		"results": results,
		"count":   len(results),
	})
}

// handleStatus 处理状态查询
func handleStatus(w http.ResponseWriter, r *http.Request) {
	respondJSON(w, indexStatus)
}

// handleFileContent 处理文件内容查看
func handleFileContent(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	
	filePath := r.URL.Query().Get("path")
	if filePath == "" {
		respondJSON(w, map[string]interface{}{
			"success": false,
			"message": "缺少文件路径参数",
		})
		return
	}
	
	fmt.Printf("📖 查看文件内容: %s\n", filePath)
	
	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		respondJSON(w, map[string]interface{}{
			"success": false,
			"message": "文件不存在: " + filePath,
		})
		return
	}
	
	// 读取文件内容
	content, err := os.ReadFile(filePath)
	if err != nil {
		fmt.Printf("❌ 读取文件失败: %v\n", err)
		respondJSON(w, map[string]interface{}{
			"success": false,
			"message": "读取文件失败: " + err.Error(),
		})
		return
	}
	
	// 检测文件编码并转换
	contentStr := string(content)
	
	// 获取文件信息
	fileInfo, _ := os.Stat(filePath)
	
	// 按行分割内容，便于前端显示行号
	lines := strings.Split(contentStr, "\n")
	
	fmt.Printf("✅ 文件读取成功，共 %d 行\n", len(lines))
	
	respondJSON(w, map[string]interface{}{
		"success":    true,
		"file_path":  filePath,
		"file_name":  filepath.Base(filePath),
		"file_size":  fileInfo.Size(),
		"modified_at": fileInfo.ModTime().Format("2006-01-02 15:04:05"),
		"content":    contentStr,
		"lines":      lines,
		"line_count": len(lines),
	})
}

// handleStatic 处理静态文件
func handleStatic(w http.ResponseWriter, r *http.Request) {
	http.NotFound(w, r)
}

// respondJSON 返回JSON响应
func respondJSON(w http.ResponseWriter, data interface{}) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	json.NewEncoder(w).Encode(data)
}